from datetime import datetime
from logging import getLogger

from django.conf import settings
from django.core.paginator import Paginator, EmptyPage
from django.http import HttpResponseNotFound, JsonResponse, \
    HttpResponseForbidden, HttpResponseServerError
from django.shortcuts import render
from django.utils import timezone
from django.views import View

from content.utils import get_goods_catetory, get_breadcrumb
from goods.models import GoodsCategory, SKU, GoodsVisitCount

logger = getLogger('django')


class Goods(View):
    """
    商品展示
    """

    def get(self, request, id, page):
        """
        商品列表页
        :param request: list/id/page/?sort=default
        :param id: 商品类别号
        :param page: 分页页码
        :return: 列表页
        """
        # print(id)
        try:
            category = GoodsCategory.objects.get(id=id)
        except GoodsCategory.DoesNotExist:
            return HttpResponseNotFound('参数category_id不存在')
        except Exception as e:
            logger.error('[数据库错误] %s [查询商品类别(%s)] 失败' % (e, id))
            # print('查询商品类别失败')
            return HttpResponseNotFound('拒绝访问')

        sort = request.GET.get('sort', 'default')
        if sort == 'price':
            sort_field = 'price'  # 按照价格由低到高排序
        elif sort == 'hot':
            sort_field = '-sales'  # 按照销量由高到低排序
        else:
            sort = 'default'
            sort_field = 'create_time'

        # 分页和排序查询
        try:
            skus = category.sku_set.filter(is_launched=True).order_by(
                sort_field)
            # print(skus)
        except SKU.DoesNotExist:
            return HttpResponseNotFound('没有商品')
        except Exception as e:
            logger.error('[数据库错误] %s [查询商品(%s)] 失败' % (e, category))
          # print('查询商品失败')
            return HttpResponseNotFound('拒绝访问')

        # 创建分页器
        # Paginator('要分页的记录', '每页记录的条数')
        paginator = Paginator(skus, settings.PAGE_SIZE)
        # 获取到用户当前要看的那一页（核心数据）
        try:
            page_skus = paginator.page(page)  # 获取到page页中的五条记录
        except EmptyPage:
            return HttpResponseNotFound('Empty Page')
        # 获取总页数：前端的分页插件需要使用
        total_page = paginator.num_pages

        data = {
            'categories': get_goods_catetory(),
            'breadcrumb': get_breadcrumb(category),
            'page_skus': page_skus,
            'total_page': total_page,
            'page_num': page,
            'sort': sort,
            'category_id': id
        }
        # return HttpResponseNotFound('顺利通过')
        return render(request, 'list.html', data)


class HotGoodsView(View):
    """热销排行"""

    def get(self, request, category_id):
        # 查询指定分类的SKU信息，而且必须是上架的状态，然后按照销量由高到低排序，最后切片取出两位
        skus = SKU.objects.filter(category_id=category_id,
                                  is_launched=True).order_by('-sales')[:2]
        # 将模型列表转字典列表，构造JSON数据
        hot_skus = []
        for sku in skus:
            sku_dict = {
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'default_image_url': sku.default_image.url  # 记得要取出全路径
            }
            hot_skus.append(sku_dict)

        return JsonResponse({'code': 0, 'errmsg': 'OK', 'hot_skus': hot_skus})


class DetailView(View):
    """商品详情页"""

    def get(self, request, sku_id):
        """提供商品详情页"""
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return render(request, '404.html')

        # 查询商品频道分类
        categories = get_goods_catetory()
        # 查询面包屑导航
        breadcrumb = get_breadcrumb(sku.category)

        # 构建当前商品的规格键
        sku_specs = sku.specs.order_by('spec_id')
        sku_key = []
        for spec in sku_specs:
            sku_key.append(spec.option.id)

        # 获取当前商品的所有SKU
        skus = sku.spu.sku_set.all()
        # 构建不同规格参数（选项）的sku字典
        spec_sku_map = {}
        for s in skus:
            # 获取sku的规格参数
            s_specs = s.specs.order_by('spec_id')

            # 用于形成规格参数-sku字典的键
            key = []
            for spec in s_specs:
                key.append(spec.option.id)
                # 向规格参数-sku字典添加记录
                spec_sku_map[tuple(key)] = s.id

        # 获取当前商品的规格信息
        goods_specs = sku.spu.specs.order_by('id')
        # 若当前sku的规格信息不完整，则不再继续
        if len(sku_key) < len(goods_specs):
            return

        for index, spec in enumerate(goods_specs):
            # 复制当前sku的规格键
            key = sku_key[:]
            # 该规格的选项
            spec_options = spec.options.all()
            for option in spec_options:
                # 在规格参数sku字典中查找符合当前规格的sku
                key[index] = option.id
                option.sku_id = spec_sku_map.get(tuple(key))
                spec.spec_options = spec_options

        # 渲染页面
        context = {
            'categories': categories,
            'breadcrumb': breadcrumb,
            'sku': sku,
            'specs': goods_specs,
        }
        return render(request, 'detail.html', context)


class DetailVisitView(View):
    """统计分类商品的访问量"""

    def post(self, request, id):
        # 接收参数和校验参数
        try:
            category = GoodsCategory.objects.get(id=id)
        except GoodsCategory.DoesNotExist:
            return HttpResponseForbidden('category_id 不存在')
        # 获取当天的日期
        t = timezone.localtime()
        # print(t)
        # 获取当天的时间字符串
        today_str = '%d-%02d-%02d' % (t.year, t.month, t.day)
        # 将当天的时间字符串转成时间对象datetime，为了跟date字段的类型匹配 2019:05:23 2019-05-23
        today_date = datetime.strptime(today_str, '%Y-%m-%d')
        # 时间字符串转时间对象；datetime.strftime() # 时间对象转时间字符串
        # 判断当天中指定的分类商品对应的记录是否存在
        try:
            # 如果存在，直接获取到记录对应的对象
            counts_data = GoodsVisitCount.objects.get(date=today_date,
                                                      category=category)
        except GoodsVisitCount.DoesNotExist:
            # 如果不存在，直接创建记录对应的对象
            counts_data = GoodsVisitCount()
            counts_data.category = category
            counts_data.date = today_date

        try:
            counts_data.count += 1
            counts_data.save()
        except Exception as e:
            logger.error('[数据库错误] %s [统计(%s)商品浏览数] 失败' % (e, category))
            return HttpResponseServerError('统计失败')

        # 响应结果
        return JsonResponse({'code': 0, 'errmsg': 'OK'})



"""
sudo docker run --name mysql-slave -e MYSQL_ROOT_PASSWORD=123456 -d --network=host -v ~/mysql_slave/data:/var/lib/mysql -v ~/mysql_slave/mysql.conf.d:/etc/mysql/mysql.conf.d mysql
sudo docker run --name mysql-slave -p 127.0.0.1:8306 -e MYSQL_ROOT_PASSWORD=mysql -d --network=host -v /home/sixstar/mysql_slave/data:/var/lib/mysql -v /home/sixstar/mysql_slave/mysql.conf.d:/etc/mysql/mysql.conf.d mysql:5.7.34
"""
